/*
	Copyright (c) 2010 <copyright holders>
	This source code is licensed under The MIT License,
	see the file LICENSE for details.
	*/

#include "FrameHandler.hpp"

#include <OGRE/OgreRenderWindow.h>
#include <OIS/OIS.h>
#include <QuickGUI.h>

#include "CameraMan.hpp"
#include "Game.hpp"
#include "GameGUI.hpp"
#include "Net.hpp"
#include "Presentation.hpp"
#include "WorldInputHandler.hpp"
#include "WorldManager.hpp"

namespace spelprog2 {

FrameHandler::FrameHandler(Game & game) :
      game_(game),
      inputMan(NULL),
      mouse(NULL),
      mouseX_(),
      mouseY_(),
      keyboard(NULL),
      quit_(false)
{
    size_t wndHandle;
    game_.getWindow().getCustomAttribute("WINDOW", &wndHandle);
    inputMan = OIS::InputManager::createInputSystem(wndHandle);
    mouse = static_cast<OIS::Mouse *>(inputMan->createInputObject(OIS::OISMouse, true));
    keyboard = static_cast<OIS::Keyboard *>(inputMan->createInputObject(OIS::OISKeyboard, true));
    mouse->setEventCallback(this);
    keyboard->setEventCallback(this);
    keyboard->setTextTranslation(OIS::Keyboard::Unicode);
}

FrameHandler::~FrameHandler() {
    inputMan->destroyInputObject(keyboard);
    inputMan->destroyInputObject(mouse);
    OIS::InputManager::destroyInputSystem(inputMan);
}

bool FrameHandler::frameStarted(const Ogre::FrameEvent & ev) {
    game_.present();

    mouse->getMouseState().width = game_.getViewport().getActualWidth();
    mouse->getMouseState().height = game_.getViewport().getActualHeight();

    mouse->capture();
    keyboard->capture();

    if (quit_ || keyboard->isKeyDown(OIS::KC_ESCAPE)) {
        return false;
    }

    game_.getNetworking().poll();
    
    game_.getWorldManager().update(ev.timeSinceLastFrame);

    game_.getPresentation().update(ev.timeSinceLastFrame);

    return true;
}

bool FrameHandler::frameRenderingQueued(const Ogre::FrameEvent & ev)
{
    game_.getPresentation().getCameraManager().frameRenderingQueued(ev);
    return true;
}

bool FrameHandler::keyPressed(const OIS::KeyEvent & ev)
{
    game_.getPresentation().keyPressed(ev);
    return true;
}

bool FrameHandler::keyReleased(const OIS::KeyEvent & ev)
{
    game_.getPresentation().keyReleased(ev);
    return true;
}

bool FrameHandler::mouseMoved(const OIS::MouseEvent & ev) {
    int x, y, w, h;
    game_.getViewport().getActualDimensions(x, y, w, h);

    float minX = float(x);
    float maxX = float(x + w);
    float minY = float(y);
    float maxY = float(y + h);
    
    mouseX_ += ev.state.X.rel; //TODO: scale by mouse sens?
    mouseY_ += ev.state.Y.rel;

    mouseX_ = std::max(mouseX_, minX);
    mouseX_ = std::min(mouseX_, maxX);
    mouseY_ = std::max(mouseY_, minY);
    mouseY_ = std::min(mouseY_, maxY);

    game_.getPresentation().mouseMoved(Ogre::Vector2(mouseX_, mouseY_),
        Ogre::Vector2(getNormalizedMouseX(), getNormalizedMouseY()), ev);
    return true;
}

bool FrameHandler::mousePressed(const OIS::MouseEvent & ev, OIS::MouseButtonID id)
{
    game_.getPresentation().mousePressed(Ogre::Vector2(mouseX_, mouseY_),
        Ogre::Vector2(getNormalizedMouseX(), getNormalizedMouseY()), ev, id);
    return true;
}

bool FrameHandler::mouseReleased(const OIS::MouseEvent & ev, OIS::MouseButtonID id)
{
    game_.getPresentation().mouseReleased(Ogre::Vector2(mouseX_, mouseY_),
        Ogre::Vector2(getNormalizedMouseX(), getNormalizedMouseY()), ev, id);
    return true;
}

float FrameHandler::getNormalizedMouseX() const
{
    return mouseX_ / game_.getViewport().getActualWidth();
}

float FrameHandler::getNormalizedMouseY() const
{
    return mouseY_ / game_.getViewport().getActualHeight();
}

}; //namespace spelprog2
